home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / TurboTCP 2.0.1 / TurboTCP source / CTCPDriver.cp < prev    next >
Encoding:
Text File  |  1994-11-21  |  11.5 KB  |  516 lines  |  [TEXT/MPCC]

  1. /*
  2. ** CTCPDriver.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP driver interface class
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11. #include "CTCPDriver.h"
  12.  
  13. #include "CApplication.h"
  14. #include "CBartender.h"
  15. #include "CDLOGDirector.h"
  16. #include "CPtrArray.h"
  17. #include "CVoidPtrArrayIterator.h"
  18.  
  19. #if (defined(GENERATINGPOWERPC) || defined(GENERATING68K))
  20. #include <MacTCP.h>                            // Universal Headers 2.0
  21. #else
  22. #include <GetMyIPAddr.h>                        // Univ Headers 1.0 or old headers
  23. #endif
  24.  
  25. #include "CTCPApplication.h"
  26. #include "CTCPAsyncCall.h"
  27. #include "CTCPStream.h"
  28. #include "CTCPResolverCall.h"
  29.  
  30.  
  31. // resource definitions
  32.  
  33. #define DLOG_TCPDelayedQuit    23010
  34.  
  35.  
  36. // TCL global variables
  37.  
  38. extern CApplication*    gApplication;
  39. extern CBartender*        gBartender;
  40.  
  41.  
  42. // CTCPDriver static variables
  43.  
  44. CTCPDriver*            CTCPDriver::gTCPDriver = NULL;
  45.  
  46.  
  47. // declare special list classes used here
  48.  
  49. #ifndef TCL_NO_TEMPLATES
  50.     class CTCPStreamList : public CPtrArray<CTCPStream> {};
  51.     class CTCPResolverCallList : public CPtrArray<CTCPResolverCall> {};
  52. #else
  53.     CW_Decl_PtrArray(CTCPStream)
  54.     CW_Decl_PtrArray(CTCPResolverCall)
  55. #endif
  56.  
  57.  
  58. //______________________________________________________________________
  59. //
  60. //    All routines are private interfaces for the use of TurboTCP classes ONLY!
  61. //    They are subject to change in future versions. Be forewarned!
  62. //
  63. //______________________________________________________________________
  64.  
  65.  
  66. //    —— contructor/destructor ——
  67.  
  68. /*______________________________________________________________________
  69. **
  70. ** constructor
  71. **
  72. **    Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
  73. **    resolver.
  74. **
  75. **        doOpenResolver (Boolean):    TRUE to open TCP resolver as well
  76. **
  77. */
  78.  
  79. CTCPDriver::CTCPDriver()
  80.  
  81. {
  82.  
  83.     // clear variables
  84.     
  85.     hasMacTCP = FALSE;
  86.     hasResolver = FALSE;
  87.     myTCPRefNum = 0;
  88.     myIPAddress = 0L;
  89.     gTCPDriver = this;
  90.     activeStreamList = NULL;
  91.     activeResolverList = NULL;
  92.  
  93.     
  94.     // if on PowerPC, get completion procedure (which is 68K code)
  95.  
  96.     CTCPAsyncCall::GetCompletionProc();
  97.     
  98.     
  99.     // clear asynch processing queue
  100.     
  101.     asyncQueue.qFlags = 0;
  102.     asyncQueue.qHead = NULL;
  103.     asyncQueue.qTail = NULL;
  104.  
  105.  
  106.     // create the active TCP/DNR call lists
  107.     
  108.     activeStreamList = new CTCPStreamList;
  109.     activeResolverList = new CTCPResolverCallList;
  110.  
  111. }
  112.  
  113.  
  114. /*______________________________________________________________________
  115. **
  116. ** Dispose
  117. **
  118. **    Dispose of this object and any lingering TCP async call objects or TCP stream objects.
  119. **    It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
  120. **    otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
  121. **    If the resolver is open, wait until all resolver queries have been cancelled.
  122. **
  123. **    If at least one second elapses between the start of this routine and the end, flash a
  124. **    dialog box to indicate the reason for the delay.
  125. **
  126. **    The ‘Dispose’ method is retained in TCL 2.0 because the driver object may need to
  127. **    delay its destruction.
  128. **
  129. */
  130.  
  131. void CTCPDriver::Dispose()
  132.  
  133. {
  134.     register long        i;
  135.     void*            theStreamPtr;
  136.     CTCPStream*        theStream;
  137.     unsigned long        startTickCount;
  138.     unsigned long        theTime;
  139.     CDLOGDirector*    theDialog = NULL;
  140.  
  141.  
  142.     
  143.     // cancel outstanding DNR calls & close resolver
  144.     
  145.     if (hasResolver)
  146.         CTCPResolverCall::CloseResolver();
  147.  
  148.  
  149.     // kill any lingering streams
  150.     
  151.     if (activeStreamList) {
  152.         CVoidPtrArrayIterator streams(activeStreamList, kStartAtBeginning);
  153.             
  154. //        CTCPStreamIterator streams(activeStreamList, kStartAtBeginning);
  155. //        #ifndef TCL_NO_TEMPLATES
  156. //            CPtrArrayIterator<CTCPStream> streams(activeStreamList, kStartAtBeginning);
  157. //        #else
  158. //            CPtrArrayIterator_CTCPStream streams(activeStreamList, kStartAtBeginning);
  159. //        #endif
  160.         
  161.         while (streams.Next(theStreamPtr)) {
  162.             theStream = (CTCPStream*&) theStreamPtr;
  163.             theStream->PostponeDispose();
  164.         }
  165.     }
  166.  
  167.  
  168.     // wait for TCP to be done with everything
  169.     
  170.     GetDateTime(&startTickCount);
  171.     gBartender->DisableMenuBar();                    // disable all menus
  172.     
  173.     while (!activeStreamList->IsEmpty()) {
  174.  
  175.  
  176.         // do a private event loop & toss up a dialog if it takes more than 2 seconds
  177.         
  178.         GetDateTime(&theTime);
  179.         if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
  180.             theDialog = new CDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
  181.             theDialog->BeginDialog();
  182.         }
  183.  
  184.                 
  185.         // wait for TCP completions & terminations
  186.         
  187.         gApplication->Process1Event();
  188.  
  189.     }
  190.     
  191.     
  192.     // get rid of dialog box (if there was one)
  193.     
  194.     ForgetObject(theDialog);
  195.  
  196.     
  197.     // dispose all the objects
  198.     
  199.     ForgetObject(activeStreamList);
  200.     ForgetObject(activeResolverList);
  201.     delete this;
  202.  
  203. }
  204.  
  205.  
  206. //    —— event handling ——
  207.  
  208. /*______________________________________________________________________
  209. **
  210. ** ProcessOneNetEvent
  211. **
  212. **    Respond to all delayed TCP notifications, completions, disposals. This routine should be
  213. **    hooked into the application’s event loop or some very frequently called routine.
  214. **
  215. **        return (Boolean):    TRUE if there are more asynchronous events in the queue
  216. **
  217. */
  218.  
  219. Boolean CTCPDriver::ProcessOneNetEvent()
  220.  
  221. {
  222.     void*            theAsyncObject;
  223.     TurboTCPQElemPtr    theAsyncEntry;
  224.     CTCPAsyncCall*    theAsyncCall;
  225.     CTCPResolverCall*    theResolverCall;
  226.     CTCPStream*        theStream;
  227.     
  228.     
  229.     // if no events, quit now
  230.  
  231.     if (asyncQueue.qHead == NULL)
  232.         return FALSE;
  233.  
  234.  
  235.     // figure out what object caused the notification
  236.  
  237.     theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
  238.     theAsyncObject = (CCollaborator*) theAsyncEntry->qSelfLink;
  239.  
  240.  
  241.     // remove it from the queue (just in case the event processing fails)
  242.     
  243.     Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
  244.     
  245.     
  246.     // process the event
  247.  
  248.     switch (theAsyncEntry->qType) {
  249.         case asyncCall:
  250.             theAsyncCall = (CTCPAsyncCall*) theAsyncObject;
  251.             if (theAsyncCall)
  252.                 theAsyncCall ->ProcessCompletion();
  253.             break;
  254.         case resolverCall:
  255.             theResolverCall = (CTCPResolverCall*) theAsyncObject;
  256.             if (theResolverCall)
  257.                 theResolverCall->ProcessNotify();
  258.             break;
  259.         case notifyStream:
  260.             theStream = (CTCPStream*) theAsyncObject;
  261.             if (theStream)
  262.                 theStream->ProcessNotify();
  263.             break;
  264.         case disposeStream:
  265.             theStream = (CTCPStream*) theAsyncObject;
  266.             if (theStream)
  267.                 theStream->Dispose();
  268.             break;
  269.  
  270.     }    // switch
  271.  
  272.     
  273.     // tell caller whether there’s another call
  274.     
  275.     return (asyncQueue.qHead != NULL);
  276.  
  277. }
  278.  
  279.  
  280. //    —— TCP verification routines ——
  281.  
  282. /*______________________________________________________________________
  283. **
  284. ** GetIPAddr (public static method)
  285. **
  286. **    Returns the current local IP address, if available. Fails with “noTCPError” error if
  287. **    MacTCP is not installed.
  288. **
  289. **        return (ip_addr):     current IP address
  290. **
  291. */
  292.  
  293. ip_addr CTCPDriver::GetIPAddr()
  294.  
  295. {
  296.     if (!(gTCPDriver->hasMacTCP))
  297.         FailOSErr(noTCPError);
  298.     return gTCPDriver->myIPAddress;
  299. }
  300.  
  301.  
  302. /*______________________________________________________________________
  303. **
  304. ** CheckTCPDriver
  305. **
  306. **    Check to see if the MacTCP driver is present. Should be done before opening each new
  307. **    connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
  308. **
  309. **        return (Boolean):    TRUE if MacTCP driver is present
  310. **
  311. */
  312.  
  313. Boolean CTCPDriver::CheckTCPDriver()
  314.  
  315. {
  316.     ParamBlockRec    theParamBlock;
  317.     unsigned char    theName[6] = "\p.IPP";        // MacTCP driver name
  318.  
  319.  
  320.     // if TCP not already confirmed, look for it
  321.     
  322.     if (!hasMacTCP) {
  323.         theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
  324.         theParamBlock.ioParam.ioPermssn = fsCurPerm;
  325.         if ((short) PBOpenSync(&theParamBlock) == 0) {
  326.             myTCPRefNum = theParamBlock.ioParam.ioRefNum;
  327.             hasMacTCP = TRUE;
  328.         }
  329.     }
  330.  
  331.  
  332.     /*
  333.     **    If TCP driver available, get the IP address. This is done *each* time a new stream
  334.     **    is created because the address might have changed. (This could happen on a machine
  335.     **    connected by modem & SLIP, if the user hangs up the modem and re-dials the
  336.     **    SLIP server without quitting the program.)
  337.     */
  338.     
  339.     FetchIPAddr();
  340.     return hasMacTCP;
  341.  
  342. }
  343.  
  344.  
  345. /*______________________________________________________________________
  346. **
  347. ** CheckResolver
  348. **
  349. **    Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
  350. **    call to make it available.
  351. **
  352. **        return (Boolean):    TRUE if TCP resovler is present
  353. **
  354. */
  355.  
  356. Boolean CTCPDriver::CheckResolver()
  357.  
  358. {
  359.  
  360.     TRY {
  361.         CTCPResolverCall::OpenResolver();
  362.         hasResolver = TRUE;
  363.     }
  364.     CATCH {
  365.         hasResolver = FALSE;
  366.         NO_PROPAGATE;
  367.     }
  368.     ENDTRY;
  369.     return hasResolver;
  370.  
  371. }
  372.  
  373.  
  374. /*______________________________________________________________________
  375. **
  376. ** GetTCPRefNum
  377. **
  378. **    Returns the Device Manager reference number for MacTCP, if available. Fails with
  379. **    “noTCPError” error if not available.
  380. **
  381. **        return (short):     MacTCP driver refnum
  382. **
  383. */
  384.  
  385. short CTCPDriver::GetTCPRefNum()
  386.  
  387. {
  388.     if (!(gTCPDriver->hasMacTCP))
  389.         FailOSErr(noTCPError);
  390.     return gTCPDriver->myTCPRefNum;
  391. }
  392.  
  393.  
  394. /*______________________________________________________________________
  395. **
  396. ** FetchIPAddr (protected method)
  397. **
  398. **    Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
  399. **    new address in the local field myIPAddress, which can be retrieved with the
  400. **    GetIPAddr() method.
  401. **
  402. */
  403.  
  404. void CTCPDriver::FetchIPAddr()
  405.  
  406. {
  407.     struct GetAddrParamBlock theIPParamBlock;
  408.  
  409.     myIPAddress = 0L;
  410.  
  411.     if (hasMacTCP) {
  412.         theIPParamBlock.csCode = ipctlGetAddr;
  413.         theIPParamBlock.ioCRefNum = myTCPRefNum;
  414.         PBControlSync((ParmBlkPtr) &theIPParamBlock);
  415.         if (theIPParamBlock.ioResult == noErr)
  416.             myIPAddress = theIPParamBlock.ourAddress;
  417.     }
  418. }
  419.  
  420.  
  421. //    —— tracking active streams/resolvers ——
  422.  
  423. /*______________________________________________________________________
  424. **
  425. ** RegisterActiveStream
  426. **
  427. **    Add a DNR resolver call to the list of active TCP streams. The driver object uses this
  428. **    information to ensure that all resolver calls are closed and terminated before the
  429. **    application quits.
  430. **
  431. **        theStream (CTCPStream*):    the stream to register
  432. **
  433. */
  434.  
  435. void CTCPDriver::RegisterActiveStream(CTCPStream* theStream)
  436.  
  437. {
  438.     activeStreamList->Append(theStream);
  439. }
  440.  
  441.  
  442. /*______________________________________________________________________
  443. **
  444. ** RegisterActiveResolver
  445. **
  446. **    Add a DNR resolver call to the list of active TCP streams. The driver object uses this
  447. **    information to ensure that all resolver calls are closed and terminated before the
  448. **    application quits.
  449. **
  450. **        theResolver (CTCPResolverCall*):    the resolver call to register
  451. **
  452. */
  453.  
  454. void CTCPDriver::RegisterActiveResolver(CTCPResolverCall* theResolver)
  455.  
  456. {
  457.     if (CheckResolverLimit())                        // disallow 9th DNR call
  458.         FailOSErr(resolverBusy);
  459.     activeResolverList->Append(theResolver);
  460. }
  461.  
  462.  
  463. /*______________________________________________________________________
  464. **
  465. ** RemoveActiveStream
  466. **
  467. **    Remove a TCP stream from the list of active TCP streams. This message indicates that
  468. **    MacTCP is no longer dependent on the memory structure for the stream.
  469. **
  470. **        theStream (CTCPStream*):    the stream to remove
  471. **
  472. */
  473.  
  474. void CTCPDriver::RemoveActiveStream(CTCPStream* theStream)
  475.  
  476. {
  477.     if (activeStreamList)                        // just in case this is called during shutdown
  478.         activeStreamList->Remove(theStream);
  479. }
  480.  
  481.  
  482. /*______________________________________________________________________
  483. **
  484. ** RemoveActiveResolver
  485. **
  486. **    Remove a DNR resolver call from the list of active calls. This message indicates that
  487. **    the MacTCP DNR is no longer dependent on the memory structure for the call.
  488. **
  489. **        theResolver (CTCPResolverCall*):    the resolver call to remove
  490. **
  491. */
  492.  
  493. void CTCPDriver::RemoveActiveResolver(CTCPResolverCall* theResolver)
  494.  
  495. {
  496.     if (activeResolverList)                        // just in case this is called during shutdown
  497.         activeResolverList->Remove(theResolver);
  498. }
  499.  
  500.  
  501. /*______________________________________________________________________
  502. **
  503. ** CheckResolverLimit
  504. **
  505. **    Ensure that the DNR’s limit of 8 calls is not violated.
  506. **
  507. **        return (Boolean):    TRUE if too many calls have been issued
  508. **
  509. */
  510.  
  511. Boolean CTCPDriver::CheckResolverLimit()
  512.  
  513. {
  514.     return (activeResolverList->numItems) >= maxResolverCalls;
  515. }
  516.